package stableproject;

import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import javax.swing.JFileChooser;
import javax.swing.JFrame;

/**
 * A main class for running the project
 **/

public class Main {

	public NodeBank nodeBank;

	public Main() {
		nodeBank = new NodeBank();

		chooseFiles();
		populateBank();
		nodeBank.printAll();

	}

	/**
	 * Method or choosing files
	 */
	private void chooseFiles() {
		JFileChooser fc = new JFileChooser();

		fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		fc.showOpenDialog(new JFrame());

		// creates an input stream for the file to be parsed
		File file = fc.getSelectedFile();

		/* Directory */
		if (file.isDirectory())
			checkInsideFolder(file);

		else
			try {
				nodeBank.addNode(new Node(parseFile(file), file.getName()));
			} catch (NullCompilationUnitException e) {
				// System.out.println("* ERROR: wrong file type " +
				// file.getName());
			}

	}

	/**
	 * Iterate through folders
	 * 
	 * @param file
	 */
	private void checkInsideFolder(File file) {
		for (File child : file.listFiles()) {

			if (child.isDirectory())
				checkInsideFolder(child);

			try {
				nodeBank.addNode(new Node(parseFile(child), child.getName()));
			} catch (NullCompilationUnitException e) {
				// System.out.println("* ERROR: wrong file type " +
				// child.getName());

			}
		}
	}

	/**
	 * Populate the node bank
	 */
	private void populateBank() {

		MethodVisitor mv = new MethodVisitor();
		ClassVisitor cv = new ClassVisitor<String>();

		for (Node n : nodeBank.bank) {
			mv.cleanse();

			if (n.compUnit != null) {

				// Seup visitors
				mv.visit(n.compUnit, null);
				cv.visit(n.compUnit, null);

				// add clasname
				n.setName((String) cv.name);

				// add extends
				n.setExtends((String) cv.extendz);

				// clone public methods to the node
				for (String s : mv.publicMethods)
					n.addPublicMethod(s);

				// add method list to a hashmap
				n.setmethodHash(mv.methodList);

			}
		}

		/* After analysed the files re-iterate through */
		for (Node n : nodeBank.bank) {

			setNOC(n);

			setDIT(n);
		}

	}

	/**
	 * Set the DIT
	 * 
	 * @param n
	 */
	private void setDIT(Node n) {
		// set DIT
		if (n.extendz != null && !n.extendz.matches(""))
			n.setDIT((getTree((java.lang.String) n.name)));

		else
			n.setDIT(1);
	}

	/**
	 * Set the number of children
	 * 
	 * @param n
	 */
	private void setNOC(Node n) {
		int kids = 0;

		// identify if any classes extend n
		for (Node n2 : nodeBank.bank)
			if (n2.getExtends().matches(n.getClassName()))
				kids++;

		n.setNoKids(kids);
	}

	/**
	 * Count the next level up the inheritance tree
	 * 
	 * @param leaf
	 * @return
	 */
	public int getTree(String leaf) {
		int count = 1;

		if (nodeBank.hasClass(leaf)) {

			count = count
					+ getTree((java.lang.String) nodeBank.getExendsList(leaf));

		}

		else
			return 1;

		return count;
	}

	/**
	 * Create a compilation for the file
	 */
	private CompilationUnit parseFile(File f) {

		if (f.getName().endsWith(".java")) {

			FileInputStream in = null;
			try {
				in = new FileInputStream(f.getAbsolutePath());
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			try {
				// parse the file
				try {
					return JavaParser.parse(in);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} finally {
				try {
					in.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		return null;
	}

}
